import Transformer from '.';
import { dist, distancePoints, intersectionPoint, midpoint, nodesTreeToList, slope, vectorRotation } from '@/utils';
import { pointsName, cPointsName } from './constant';

/**
 * 旋转开始事件
 * @param {MouseEvent} e
 * @this {Transformer}
 */
export function onRotateStart(e) {
  this.lastGridCoord = this.stage.gridCoord;
  this.rotating = true;
  window.addEventListener('mousemove', this.onRotate);
  window.addEventListener('mouseup', this.onRotateEnd);
}

/**
 * 旋转事件
 * @param {MouseEvent} e
 * @this {Transformer}
 */
export function onRotate(e) {
  // 鼠标未处于按下状态，结束旋转事件
  if (e?.buttons === 0) {
    this.onRotateEnd(e);
    return;
  }
  const { lastGridCoord, center, stage } = this;
  const { gridCoord } = stage;
  const lastRotation = vectorRotation(center, lastGridCoord);
  const rotation = vectorRotation(center, gridCoord);
  // const diffRotation = rotation - lastRotation;
  const diffRotation = Math.round(rotation) - Math.round(lastRotation); // 角度强制取整
  // shift键按下 设置最终旋转角度以 15° 为单位
  if (e?.shiftKey) if (Math.abs(diffRotation) % 15 !== 0) return;
  this.rotate(this.rotation + diffRotation, false);
  this.lastGridCoord = gridCoord;
}

/**
 * 旋转结束事件
 * @param {MouseEvent} e
 * @this {Transformer}
 */
export function onRotateEnd(e) {
  // 鼠标仍然处于按下状态，维持拖动状态
  if (e.buttons > 0) return;
  this.rotating = false;
  // 记录画布历史状态
  this.stage._handleRecord();
  window.removeEventListener('mousemove', this.onRotate);
  window.removeEventListener('mouseup', this.onRotateEnd);
}

/**
 * 调整大小开始事件
 * @param {MouseEvent} e
 * @param {string} anchorName
 * @this {Transformer}
 */
export function onResizeStart(e, anchorName) {
  this.anchorName = anchorName;
  this.lastGridCoord = this.stage.gridCoord;
  this.resizing = true;
  window.addEventListener('mousemove', this.onResize);
  window.addEventListener('mouseup', this.onResizeEnd);
}

/**
 * 调整大小事件
 * @param {MouseEvent} e
 * @this {Transformer}
 */
export function onResize(e) {
  // 鼠标未处于按下状态，结束调整大小事件
  if (e?.buttons === 0) {
    this.onResizeEnd(e);
    return;
  }
  const { anchorName, lastGridCoord, nodes, points, edges, cPoints, center, width, height, stage } = this;
  const { gridCoord } = stage;
  const { x: lastX, y: lastY } = lastGridCoord;
  const { x, y } = gridCoord;
  const offset = { x: x - lastX, y: y - lastY };
  const index = pointsName.indexOf(anchorName);
  const cIndex = cPointsName.indexOf(anchorName);
  // 是否固定宽高比
  let lockAspectRatio = true;
  // 单个转换节点
  if (nodes.length === 1) {
    // 图片节点 且 非固定宽高比 => 不固定宽高比
    if (nodes[0].className === 'Image' && !nodes[0].lockAspectRatio) lockAspectRatio = false;
    // 文本节点 且 调整中心锚点 => 不固定宽高比
    if (nodes[0].className === 'Text' && cIndex > 0) lockAspectRatio = false;
  }
  if (index >= 0) {
    const point = points[index];
    let finalPoint = { x: point.x + offset.x, y: point.y + offset.y };
    const lastPoint = points[(index + 3) % 4];
    const nextPoint = points[(index + 1) % 4];
    const diagonalPoint = points[(index + 2) % 4];
    const lastLineK = slope(lastPoint, point);
    const nextLineK = -(1 / lastLineK);
    // 固定宽高比：目标点只能处于对角线上
    if (lockAspectRatio) {
      const diagonalLineK = slope(diagonalPoint, point);
      finalPoint = intersectionPoint(diagonalPoint, diagonalLineK, finalPoint, -(1 / diagonalLineK));
    }
    // 确保新的目标点处于正确区域：上一个对边与下一个对边夹角区域
    const baseRotation = vectorRotation(diagonalPoint, lastPoint);
    let newRotation = vectorRotation(diagonalPoint, finalPoint);
    if (baseRotation - newRotation > 270) newRotation += 360;
    if (newRotation <= baseRotation || newRotation >= baseRotation + 90) finalPoint = point;
    // 根据两条点斜式直线交点得到更新后的相邻点坐标
    const newLastPoint = intersectionPoint(diagonalPoint, -(1 / lastLineK), finalPoint, lastLineK);
    const newNextPoint = intersectionPoint(diagonalPoint, -(1 / nextLineK), finalPoint, nextLineK);
    (point.x = finalPoint.x), (point.y = finalPoint.y);
    (lastPoint.x = newLastPoint.x), (lastPoint.y = newLastPoint.y);
    (nextPoint.x = newNextPoint.x), (nextPoint.y = newNextPoint.y);
    this.lastGridCoord = finalPoint;
  } else if (cIndex >= 0) {
    const aspectRatio = width / height; // 宽高比
    const cPoint = cPoints[cIndex];
    let finalPoint = { x: cPoint.x + offset.x, y: cPoint.y + offset.y };
    const { o, d } = edges[cIndex];
    const k = slope(o, d);
    const diagonalCPoint = cPoints[(cIndex + 2) % 4];
    const { d: lastPoint, o: nextPoint } = edges[(cIndex + 2) % 4];
    // 确保新的目标点处于正确区域：目标方向上180°扇区内
    const baseRotation = vectorRotation(diagonalCPoint, cPoint);
    let newRotation = vectorRotation(diagonalCPoint, finalPoint);
    if (Math.abs(newRotation - baseRotation) > 180) newRotation += Math.sign(baseRotation - newRotation) * 360;
    if (newRotation <= baseRotation - 90 || newRotation >= baseRotation + 90) finalPoint = cPoint;
    // 根据两条点斜式直线交点得到更新后的边端点坐标
    const newOPoint = intersectionPoint(lastPoint, -(1 / k), finalPoint, k);
    const newDPoint = intersectionPoint(nextPoint, -(1 / k), finalPoint, k);
    (o.x = newOPoint.x), (o.y = newOPoint.y), (d.x = newDPoint.x), (d.y = newDPoint.y);
    // 固定宽高比：四个顶点在垂直方向上移动一定距离以保持宽高比
    if (lockAspectRatio) {
      const newCPoint = midpoint(o, d);
      const newDistance = dist(newCPoint, diagonalCPoint);
      let distance;
      // 改变宽度方向
      if ([1, 3].includes(cIndex)) distance = newDistance / aspectRatio / 2;
      // 改变高度方向
      else distance = (newDistance * aspectRatio) / 2;
      // 获取垂直方向上距离边中点一定距离的四个点
      const [point1, point2] = distancePoints(diagonalCPoint, k, distance, lastPoint);
      const [point3, point4] = distancePoints(newCPoint, k, distance, o);
      // 更新四个顶点坐标
      (lastPoint.x = point1.x), (lastPoint.y = point1.y), (nextPoint.x = point2.x), (nextPoint.y = point2.y);
      (o.x = point3.x), (o.y = point3.y), (d.x = point4.x), (d.y = point4.y);
    }
    this.lastGridCoord = finalPoint;
  }
  const { center: newCenter, width: newWidth, height: newHeight } = this;
  const widthRatio = newWidth / width;
  const heightRatio = newHeight / height;
  const groupList = [];
  // 更新转换节点及其所有子节点大小及位置
  nodesTreeToList(nodes).forEach((node) => {
    // 忽略编组节点
    if (['Group'].includes(node.className)) {
      groupList.push(node);
      return;
    }
    // 计算更新宽高前相对父级坐标的网格坐标
    const beforeCenter = node.gridRect.center;
    // 更新节点宽高
    node.width *= widthRatio;
    node.height *= heightRatio;
    // 文本节点
    if (node.className === 'Text') {
      // 调整顶点锚点 改变文本大小
      if (index >= 0) {
        node.fontSize *= widthRatio;
        node.letterSpacing *= widthRatio;
        node.lineHeight *= widthRatio;
        node.strokeWidth *= widthRatio;
      }
      // 调整中心锚点 更新文本节点
      if (cIndex > 0) node.update();
    }
    // 计算更新宽高后相对父级坐标的网格坐标
    const afterCenter = node.gridRect.center;
    // 更新节点位置
    const resizeCenter = node.getParentCoordByGridCoord(center);
    const resizeNewCenter = node.getParentCoordByGridCoord(newCenter);
    const nodeBeforeCenter = node.getParentCoordByGridCoord(beforeCenter);
    const nodeAfterCenter = node.getParentCoordByGridCoord(afterCenter);
    const distance = dist(nodeBeforeCenter, resizeCenter) * widthRatio;
    const k = slope(nodeBeforeCenter, resizeCenter);
    // 斜率为NaN，说明调整前转换器中心点与节点中心点重合
    if (isNaN(k)) (node.x += resizeNewCenter.x - nodeAfterCenter.x), (node.y += resizeNewCenter.y - nodeAfterCenter.y);
    else {
      const [point1, point2] = distancePoints(resizeNewCenter, k, distance);
      if (Math.abs(vectorRotation(nodeBeforeCenter, resizeCenter) - vectorRotation(point1, resizeNewCenter)) < 90) {
        (node.x += point1.x - nodeAfterCenter.x), (node.y += point1.y - nodeAfterCenter.y);
      } else {
        (node.x += point2.x - nodeAfterCenter.x), (node.y += point2.y - nodeAfterCenter.y);
      }
    }
    node.emit('transform');
  });
  // 更新所有编组节点
  groupList.forEach((group) => group.update());
  // 单个转换节点
  if (nodes.length === 1) {
    // 更新父级节点
    nodes[0].updateParent();
    // 使用中心锚点转换单个文本节点后更新转换器顶点位置为实际节点顶点位置
    if (cIndex >= 0 && nodes[0].className === 'Text') this.points = nodes[0].gridRect.points;
  }
}

/**
 * 调整大小结束事件
 * @param {MouseEvent} e
 * @this {Transformer}
 */
export function onResizeEnd(e) {
  // 鼠标仍然处于按下状态，维持调整大小状态
  if (e.buttons > 0) return;
  this.resizing = false;
  // 记录画布历史状态
  this.stage._handleRecord();
  window.removeEventListener('mousemove', this.onResize);
  window.removeEventListener('mouseup', this.onResizeEnd);
}
